home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
rx
/
rxsuper.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
38KB
|
1,417 lines
/* Copyright (C) 1995, 1996 Tom Lord
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "rxall.h"
#include "rxsuper.h"
/* The functions in the next several pages define the lazy-NFA-conversion used
* by matchers. The input to this construction is an NFA such as
* is built by compactify_nfa (rx.c). The output is the superNFA.
*/
/* Match engines can use arbitrary values for opcodes. So, the parse tree
* is built using instructions names (enum rx_opcode), but the superstate
* nfa is populated with mystery opcodes (void *).
*
* For convenience, here is an id table. The opcodes are == to their inxs
*
* The lables in re_search_2 would make good values for instructions.
*/
void * rx_id_instruction_table[rx_num_instructions] =
{
(void *) rx_backtrack_point,
(void *) rx_do_side_effects,
(void *) rx_cache_miss,
(void *) rx_next_char,
(void *) rx_backtrack,
(void *) rx_error_inx
};
/* The partially instantiated superstate graph has a transition
* table at every node. There is one entry for every character.
* This fills in the transition for a set.
*/
#ifdef __STDC__
static void
install_transition (struct rx_superstate *super,
struct rx_inx *answer, rx_Bitset trcset)
#else
static void
install_transition (super, answer, trcset)
struct rx_superstate *super;
struct rx_inx *answer;
rx_Bitset trcset;
#endif
{
struct rx_inx * transitions = super->transitions;
int chr;
for (chr = 0; chr < 256; )
if (!*trcset)
{
++trcset;
chr += 32;
}
else
{
RX_subset sub = *trcset;
RX_subset mask = 1;
int bound = chr + 32;
while (chr < bound)
{
if (sub & mask)
transitions [chr] = *answer;
++chr;
mask <<= 1;
}
++trcset;
}
}
#ifdef __STDC__
static int
qlen (struct rx_superstate * q)
#else
static int
qlen (q)
struct rx_superstate * q;
#endif
{
int count = 1;
struct rx_superstate * it;
if (!q)
return 0;
for (it = q->next_recyclable; it != q; it = it->next_recyclable)
++count;
return count;
}
#ifdef __STDC__
static void
check_cache (struct rx_cache * cache)
#else
static void
check_cache (cache)
struct rx_cache * cache;
#endif
{
struct rx_cache * you_fucked_up = 0;
int total = cache->superstates;
int semi = cache->semifree_superstates;
if (semi != qlen (cache->semifree_superstate))
check_cache (you_fucked_up);
if ((total - semi) != qlen (cache->lru_superstate))
check_cache (you_fucked_up);
}
#ifdef __STDC__
char *
rx_cache_malloc (struct rx_cache * cache, int size)
#else
char *
rx_cache_malloc (cache, size)
struct rx_cache * cache;
int size;
#endif
{
char * answer;
answer = (char *)malloc (size);
if (answer)
cache->bytes_used += size;
return answer;
}
#ifdef __STDC__
void
rx_cache_free (struct rx_cache * cache, int size, char * mem)
#else
void
rx_cache_free (cache, size, mem)
struct rx_cache * cache;
int size;
char * mem;
#endif
{
free (mem);
cache->bytes_used -= size;
}
/* When a superstate is old and neglected, it can enter a
* semi-free state. A semi-free state is slated to die.
* Incoming transitions to a semi-free state are re-written
* to cause an (interpreted) fault when they are taken.
* The fault handler revives the semi-free state, patches
* incoming transitions back to normal, and continues.
*
* The idea is basicly to free in two stages, aborting
* between the two if the state turns out to be useful again.
* When a free is aborted, the rescued superstate is placed
* in the most-favored slot to maximize the time until it
* is next semi-freed.
*
* Overall, this approximates truly freeing superstates in
* lru order, but does not involve the cost of updating perfectly
* accurate timestamps every time a superstate is touched.
*/
#ifdef __STDC__
static void
semifree_superstate (struct rx_cache * cache)
#else
static void
semifree_superstate (cache)
struct rx_cache * cache;
#endif
{
int disqualified = cache->semifree_superstates;
if (disqualified == cache->superstates)
return;
while (cache->lru_superstate->locks)
{
cache->lru_superstate = cache->lru_superstate->next_recyclable;
++disqualified;
if (disqualified == cache->superstates)
return;
}
{
struct rx_superstate * it = cache->lru_superstate;
it->next_recyclable->prev_recyclable = it->prev_recyclable;
it->prev_recyclable->next_recyclable = it->next_recyclable;
cache->lru_superstate = (it == it->next_recyclable
? 0
: it->next_recyclable);
if (!cache->semifree_superstate)
{
cache->semifree_superstate = it;
it->next_recyclable = it;
it->prev_recyclable = it;
}
else
{
it->prev_recyclable = cache->semifree_superstate->prev_recyclable;
it->next_recyclable = cache->semifree_superstate;
it->prev_recyclable->next_recyclable = it;
it->next_recyclable->prev_recyclable = it;
}
{
struct rx_distinct_future *df;
it->is_semifree = 1;
++cache->semifree_superstates;
df = it->transition_refs;
if (df)
{
df->prev_same_dest->next_same_dest = 0;
for (df = it->transition_refs; df; df = df->next_same_dest)
{
df->future_frame.inx = cache->instruction_table[rx_cache_miss];
df->future_frame.data = 0;
df->future_frame.data_2 = (void *) df;
/* If there are any NEXT-CHAR instruction frames that
* refer to this state, we convert them to CACHE-MISS frames.
*/
if (!df->effects
&& (df->edge->options->next_same_super_edge[0]
== df->edge->options))
install_transition (df->present, &df->future_frame,
df->edge->cset);
}
df = it->transition_refs;
df->prev_same_dest->next_same_dest = df;
}
}
}
}
#ifdef __STDC__
static void
refresh_semifree_superstate (struct rx_cache * cache,
struct rx_superstate * super)
#else
static void
refresh_semifree_superstate (cache, super)
struct rx_cache * cache;
struct rx_superstate * super;
#endif
{
struct rx_distinct_future *df;
if (super->transition_refs)
{
super->transition_refs->prev_same_dest->next_same_dest = 0;
for (df = super->transition_refs; df; df = df->next_same_dest)
{
df->future_frame.inx = cache->instruction_table[rx_next_char];
df->future_frame.data = (void *) super->transitions;
df->future_frame.data_2 = (void *)(super->contents->is_final);
/* CACHE-MISS instruction frames that refer to this state,
* must be converted to NEXT-CHAR frames.
*/
if (!df->effects
&& (df->edge->options->next_same_super_edge[0]
== df->edge->options))
install_transition (df->present, &df->future_frame,
df->edge->cset);
}
super->transition_refs->prev_same_dest->next_same_dest
= super->transition_refs;
}
if (cache->semifree_superstate == super)
cache->semifree_superstate = (super->prev_recyclable == super
? 0
: super->prev_recyclable);
super->next_recyclable->prev_recyclable = super->prev_recyclable;
super->prev_recyclable->next_recyclable = super->next_recyclable;
if (!cache->lru_superstate)
(cache->lru_superstate
= super->next_recyclable
= super->prev_recyclable
= super);
else
{
super->next_recyclable = cache->lru_superstate;
super->prev_recyclable = cache->lru_superstate->prev_recyclable;
super->next_recyclable->prev_recyclable = super;
super->prev_recyclable->next_